home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacHack 1997
/
MacHack 1997.toast
/
Hacks
/
Hacks ’93
/
HackTV & Example panel comp.
/
softVdig.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-08-18
|
30KB
|
1,127 lines
/*
File: softVdig.c
Contains: Software video digitzer routines
Written by: Peter Hoddie (mostly) and Casey King and Gary Woodcock
Refer to develop Issue 14, "Video Digitizing Under QuickTime",
for details on this code.
This code requires QuickTime 1.5.
Copyright: © 1993 by Apple Computer, Inc.
*/
//-----------------------------------------------------------------------
// includes
#include "softVdig.h"
#include <BDC.h>
#include <FixMath.h>
#include <Errors.h>
#include <Packages.h>
#include <Fonts.h>
#include <Memory.h>
#include <ToolUtils.h>
//-----------------------------------------------------------------------
#ifdef DEBUG_IT
// Use this declaration when we're running linked (for debugging)
pascal ComponentResult softVdig (ComponentParameters *params, Handle storage)
#else
// Use this declaration when we're a standalone component
pascal ComponentResult main(ComponentParameters *params, Handle storage)
#endif DEBUG_IT
{
// This routine is the main dispatcher for the softVdig
ComponentFunction vdigProc = 0;
OSErr err = 0;
if (params->what < 0) {
switch(params->what) {
case kComponentOpenSelect: vdigProc = vdigOpen; break;
case kComponentCloseSelect: vdigProc = vdigClose; break;
case kComponentCanDoSelect: vdigProc = vdigCanDo; break;
case kComponentVersionSelect: vdigProc = vdigVersion; break;
}
}
else {
switch (params->what) {
case kSelectVDGetMaxSrcRect: vdigProc = vdigGetMaxSrcRect; break;
case kSelectVDGetActiveSrcRect: vdigProc = vdigGetActiveSrcRect; break;
case kSelectVDSetDigitizerRect: vdigProc = vdigSetDigitizerRect; break;
case kSelectVDGetDigitizerRect: vdigProc = vdigGetDigitizerRect; break;
case kSelectVDUseThisCLUT: vdigProc = vdigUseThisCLUT; break;
case kSelectVDGrabOneFrame: vdigProc = vdigGrabOneFrame; break;
case kSelectVDGetMaxAuxBuffer: vdigProc = vdigGetMaxAuxBuffer; break;
case kSelectVDGetDigitizerInfo: vdigProc = vdigGetDigitizerInfo; break;
case kSelectVDGetCurrentFlags : vdigProc = vdigGetCurrentFlags; break;
case kSelectVDSetPlayThruDestination: vdigProc = vdigSetPlayThruDestination; break;
case kSelectVDSetBrightness : vdigProc = vdigSetBrightness; break;
case kSelectVDGetBrightness : vdigProc = vdigGetBrightness; break;
case kSelectVDSetContrast : vdigProc = vdigSetContrast; break;
case kSelectVDSetHue : vdigProc = vdigSetHue; break;
case kSelectVDSetSaturation : vdigProc = vdigSetSaturation; break;
case kSelectVDSetSharpness : vdigProc = vdigSetSharpness; break;
case kSelectVDGetContrast : vdigProc = vdigGetContrast; break;
case kSelectVDGetHue : vdigProc = vdigGetHue; break;
case kSelectVDGetSaturation : vdigProc = vdigGetSaturation; break;
case kSelectVDGetSharpness : vdigProc = vdigGetSharpness; break;
case kSelectVDSetBlackLevelValue : vdigProc = vdigSetBlackLevel; break;
case kSelectVDGetBlackLevelValue : vdigProc = vdigGetBlackLevel; break;
case kSelectVDSetWhiteLevelValue : vdigProc = vdigSetWhiteLevel; break;
case kSelectVDGetWhiteLevelValue : vdigProc = vdigGetWhiteLevel; break;
case kSelectVDGetVideoDefaults : vdigProc = vdigGetVideoDefaults; break;
case kSelectVDSetPlayThruOnOff: vdigProc = vdigSetPlayThruOnOff; break;
case kSelectVDPreflightDestination: vdigProc = vdigPreflightDestination; break;
case kSelectVDSetupBuffers: vdigProc = vdigSetupBuffers; break;
case kSelectVDGrabOneFrameAsync: vdigProc = vdigGrabOneFrameAsync; break;
case kSelectVDDone: vdigProc = vdigDone; break;
case kSelectVDGetNumberOfInputs: vdigProc = vdigGetNumberOfInputs; break;
case kSelectVDGetInputFormat: vdigProc = vdigGetInputFormat; break;
case kSelectVDSetInput: vdigProc = vdigSetInput; break;
case kSelectVDGetInput: vdigProc = vdigGetInput; break;
case kSelectVDSetCompression: vdigProc = vdigSetCompression; break;
case kSelectVDCompressOneFrameAsync: vdigProc = vdigCompressOneFrameAsync; break;
case kSelectVDCompressDone: vdigProc = vdigCompressDone; break;
case kSelectVDReleaseCompressBuffer: vdigProc = vdigReleaseCompressBuffer; break;
case kSelectVDGetImageDescription: vdigProc = vdigGetImageDescription; break;
case kSelectVDResetCompressSequence: vdigProc = vdigResetCompressSequence; break;
case kSelectVDSetCompressionOnOff: vdigProc = vdigSetCompressionOnOff; break;
case kSelectVDGetCompressionTypes: vdigProc = vdigGetCompressionTypes; break;
case kSelectVDSetTimeBase: vdigProc = vdigSetTimeBase; break;
case kSelectVDSetFrameRate: vdigProc = vdigSetFrameRate; break;
case kSelectVDGetDMADepths: vdigProc = vdigGetDMADepths; break;
case kSelectVDGetPreferredTimeScale: vdigProc = vdigGetPreferredTimeScale; break;
default:
err = digiUnimpErr;
break;
}
}
if (vdigProc) {
err = CallComponentFunctionWithStorage((Handle)storage, params, vdigProc);
// kck - for debug only to catch calls that fail
if (((params->what != kSelectVDSetFrameRate) &&
(params->what != kSelectVDCompressDone) &&
(params->what != kSelectVDGetMaxAuxBuffer) &&
(params->what != kSelectVDUseThisCLUT) &&
(params->what != kSelectVDSetCompressionOnOff)
) && err ) {
return err;
}
return err;
}
bail:
return err;
}
#ifdef DEBUG_IT
Component RegisterSoftVdig(void)
{
ComponentDescription foo;
Component fooey;
Handle name;
foo.componentType = videoDigitizerComponentType;
foo.componentSubType = 'soft';
foo.componentManufacturer = 'jph ';
foo.componentFlags = 0L;
foo.componentFlagsMask = 0L;
PtrToHand ((Ptr)"\psoftVdig (Linked)", &name, 18);
fooey = RegisterComponent (&foo, (void *)softVdig, 0, name, 0, 0);
DisposHandle (name);
SetDefaultComponent (fooey, defaultComponentAnyFlagsAnyManufacturerAnySubType);
return fooey;
}
#endif DEBUG_IT
pascal ComponentResult vdigOpen(vdigGlobals storage, ComponentInstance self)
{
OSErr err;
if (CountComponentInstances((Component)self) > (short)gMaxSoftVdigCount)
return(-1);
storage = (vdigGlobals)NewHandleClear(sizeof(vdigGlobalsRecord));
if (err = MemError()) goto bail;
(**storage).self = self;
SetComponentInstanceStorage(self, (Handle)storage);
SetComponentInstanceA5(self, *(long *)0x904);
// Initialize some of the global storage members
err = vdigGetMaxSrcRect(storage, ntscIn, &(**storage).maxSrcRect);
(**storage).digiRect = (**storage).maxSrcRect;
(**storage).pendingAsyncBuffer = -1;
err = vdigGetVideoDefaults(storage,
&(**storage).blackLevel, &(**storage).whiteLevel,
&(**storage).brightness, &(**storage).hue, &(**storage).saturation,
&(**storage).contrast, &(**storage).sharpness);
// Initialize two additional softvdig configurable items
(**storage).gAttachedGDevice = 0;
SetRect(&(**storage).gAuxBufferRect,0,0,300,300);
bail:
return(err);
}
pascal ComponentResult vdigClose(vdigGlobals storage, ComponentInstance self)
{
if (storage) {
if ((**storage).tempPort)
DisposeGWorld((**storage).tempPort);
if ((**storage).auxBuffer)
DisposeGWorld((**storage).auxBuffer);
if ((**storage).bufferList)
DisposHandle((Handle)(**storage).bufferList);
if ((**storage).clipRgn)
DisposeRgn((**storage).clipRgn);
tossCompressStuff(storage);
DisposeHandle((Handle)storage);
}
return noErr;
}
pascal ComponentResult vdigCanDo(vdigGlobals storage, short ftnNumber)
{
return (ftnNumber <= kvdigSelectors) && (ftnNumber >= kComponentVersionSelect);
}
pascal ComponentResult vdigVersion(vdigGlobals storage)
{
return (vdigInterfaceRev<<16) | 1;
}
pascal VideoDigitizerError vdigGetMaxSrcRect(vdigGlobals storage, short inputStd, Rect *maxSrcRect)
{
long error = noErr;
if (inputStd == ntscIn) // softvdig supports only NTSC
SetRect(maxSrcRect, 0, 0, kMaxHorNTSCIn, kMaxVerNTSCIn + kVerBlank);
else
error = paramErr;
if (!error) (**storage).maxSrcRect = *maxSrcRect;
return error;
}
pascal VideoDigitizerError vdigGetActiveSrcRect(vdigGlobals storage, short inputStd, Rect *activeSrcRect)
{
*activeSrcRect = (**storage).maxSrcRect;
return noErr;
}
pascal VideoDigitizerError vdigSetDigitizerRect(vdigGlobals storage, Rect *digiRect)
{
Rect tempR;
// can't be empty
if (!digiRect || EmptyRect(digiRect))
return(paramErr);
// they must intersect
if (!SectRect(digiRect, &(**storage).maxSrcRect, &tempR))
return(paramErr);
// completely...
if (!EqualRect(digiRect, &tempR))
return(paramErr);
(**storage).digiRect = *digiRect;
return noErr;
}
pascal VideoDigitizerError vdigGetDigitizerRect(vdigGlobals storage, Rect *digiRect)
{
*digiRect = (**storage).digiRect;
return noErr;
}
pascal VideoDigitizerError vdigUseThisCLUT(vdigGlobals storage, CTabHandle colorTableHandle)
{
return digiUnimpErr;
}
void makeOffscreen(vdigGlobals storage)
{
OSErr err;
GWorldPtr tempPort;
Rect r;
tossOffscreen(storage);
if (!(**storage).playThruPixMap) return;
SetRect(&r, 0, 0, 4, 4);
err = NewGWorld(&tempPort, (**(**storage).playThruPixMap).pixelSize, &r, 0, 0, 0);
if (err) return;
(**storage).tempPort = tempPort;
SetRectRgn(tempPort->visRgn, -32000, -32000, 32000, 32000);
}
void tossOffscreen(vdigGlobals storage)
{
if ((**storage).tempPort) {
DisposeGWorld((**storage).tempPort);
(**storage).tempPort = 0;
}
}
void drawVideoFrame(vdigGlobals storage, Point where, PixMapHandle destPixMap)
{
Rect destRect;
CGrafPtr savePort;
GDHandle saveGD;
PixMapHandle savePortPix;
PicHandle thePict;
Rect pictRect;
Rect clipRect;
Str255 tempStr;
Point offsetClip;
RgnHandle clipRgn;
if (!(**storage).tempPort && !(**storage).compressGW) {
makeOffscreen(storage);
if (!(**storage).tempPort)
return;
}
destRect = (**storage).digiRect;
TransformRect(&(**storage).matrix, &destRect, 0);
OffsetRect(&destRect, -destRect.left + where.h, -destRect.top + where.v);
GetGWorld(&savePort, &saveGD);
if ((**storage).compressGW)
SetGWorld((**storage).compressGW, 0);
else {
SetGWorld((**storage).tempPort, 0);
savePortPix = (**storage).tempPort->portPixMap;
SetPortPix(destPixMap);
}
clipRect = (**storage).digiRect;
ClipRect(&clipRect);
pictRect = (**storage).maxSrcRect;
thePict = OpenPicture(&pictRect);
EraseRect(&pictRect);
FrameRect(&pictRect);
InsetRect(&pictRect, 10, 10);
FrameRect(&pictRect);
InsetRect(&pictRect, 10, 10);
MoveTo(pictRect.left, (pictRect.top + pictRect.bottom) >> 1);
NumToString((**storage).frameNumber, tempStr);
TextFont(helvetica);
TextSize((pictRect.bottom - pictRect.top) >> 2);
DrawString(tempStr);
ClosePicture();
if (clipRgn = (**storage).clipRgn) {
offsetClip.h = where.h - (**storage).clipOrigin.h;
offsetClip.v = where.v - (**storage).clipOrigin.v;
OffsetRgn(clipRgn, offsetClip.h, offsetClip.v);
SetClip(clipRgn);
}
else {
SetRect(&clipRect, -32000, -32000, 32000, 32000);
ClipRect(&clipRect);
}
clipRect = (**storage).maxSrcRect;
MapRect(&clipRect, &(**storage).digiRect, &destRect);
DrawPicture(thePict, &clipRect);
KillPicture(thePict);
(**storage).frameNumber++;
if (clipRgn) {
OffsetRgn(clipRgn, -offsetClip.h, -offsetClip.v);
SetRect(&clipRect, -32000, -32000, 32000, 32000);
ClipRect(&clipRect);
}
if (!(**storage).compressGW)
SetPortPix(savePortPix);
SetGWorld(savePort, saveGD);
}
pascal VideoDigitizerError vdigGrabOneFrame(vdigGlobals storage)
{
if (!(**storage).playThruPixMap)
return badCallOrder;
drawVideoFrame(storage, *(Point *)&((**storage).playThruRect), (**storage).playThruPixMap);
return noErr;
}
pascal VideoDigitizerError vdigSetContrast(vdigGlobals storage, unsigned short *contrast)
{
(**storage).contrast = *contrast;
return noErr;
}
pascal VideoDigitizerError vdigGetContrast(vdigGlobals storage, unsigned short *contrast)
{
*contrast = (**storage).contrast;
return noErr;
}
pascal VideoDigitizerError vdigSetHue(vdigGlobals storage, unsigned short *hue) {
(**storage).hue = *hue;
return noErr;
}
pascal VideoDigitizerError vdigGetHue(vdigGlobals storage, unsigned short *hue)
{
*hue = (**storage).hue;
return noErr;
}
pascal VideoDigitizerError vdigSetBrightness(vdigGlobals storage, unsigned short *brightness)
{
(**storage).brightness = *brightness;
return noErr;
}
pascal VideoDigitizerError vdigGetBrightness(vdigGlobals storage, unsigned short *brightness)
{
*brightness = (**storage).brightness;
return noErr;
}
pascal VideoDigitizerError vdigSetSaturation(vdigGlobals storage, unsigned short *saturation)
{
(**storage).saturation = *saturation;
return noErr;
}
pascal VideoDigitizerError vdigGetSaturation(vdigGlobals storage, unsigned short *saturation)
{
*saturation = (**storage).saturation;
return noErr;
}
pascal VideoDigitizerError vdigSetSharpness(vdigGlobals storage, unsigned short *sharpness)
{
(**storage).sharpness = *sharpness;
return noErr;
}
pascal VideoDigitizerError vdigGetSharpness(vdigGlobals storage, unsigned short *sharpness)
{
*sharpness = (**storage).sharpness;
return noErr;
}
pascal VideoDigitizerError vdigSetBlackLevel(vdigGlobals storage, unsigned short *blackLevel)
{
(**storage).blackLevel = *blackLevel;
return noErr;
}
pascal VideoDigitizerError vdigGetBlackLevel(vdigGlobals storage, unsigned short *blackLevel)
{
*blackLevel = (**storage).blackLevel;
return noErr;
}
pascal VideoDigitizerError vdigSetWhiteLevel(vdigGlobals storage, unsigned short *whiteLevel)
{
(**storage).whiteLevel = *whiteLevel;
return noErr;
}
pascal VideoDigitizerError vdigGetWhiteLevel(vdigGlobals storage, unsigned short *whiteLevel){
*whiteLevel = (**storage).whiteLevel;
return noErr;
}
pascal VideoDigitizerError vdigGetVideoDefaults(vdigGlobals storage,
unsigned short *blackLevel, unsigned short *whiteLevel,
unsigned short *brightness, unsigned short *hue, unsigned short *saturation,
unsigned short *contrast, unsigned short *sharpness)
{
(**storage).blackLevel = 0;
(**storage).whiteLevel = 60000;
(**storage).brightness = 20000;
(**storage).hue = 30000;
(**storage).saturation = 40000;
(**storage).contrast = 50000;
(**storage).sharpness = 60000;
return noErr;
}
pascal VideoDigitizerError vdigGetMaxAuxBuffer(vdigGlobals storage, PixMapHandle *pm, Rect *r)
{
OSErr err = noErr;
if (!gHasAuxBuffer)
return digiUnimpErr;
if (!(**storage).auxBuffer) {
GWorldPtr tempGW;
err = NewGWorld(&tempGW, gAuxDepth, &(**storage).gAuxBufferRect, 0, 0, 0);
if (err) goto bail;
LockPixels(tempGW->portPixMap);
(**storage).auxBuffer = tempGW;
}
if (pm) *pm = (**storage).auxBuffer->portPixMap;
if (r) *r = (**(**storage).auxBuffer->portPixMap).bounds;
bail:
return err;
}
pascal VideoDigitizerError vdigGetDigitizerInfo(vdigGlobals storage, DigitizerInfo *info)
{
info->vdigType = gCanClip ? vdTypeMask : vdTypeBasic;
info->inputCapabilityFlags = digiInDoesNTSC | digiInDoesComposite | digiInDoesColor;
info->outputCapabilityFlags = gDoesDepths |
(gCanScale ? digiOutDoesStretch | digiOutDoesShrink : digiOutDoesQuarter | digiOutDoesSixteenth) |
(gCanClip ? digiOutDoesMask : 0) |
(gCanDMA ? digiOutDoesHW_DMA : 0) |
(gDoesPlaythru ? digiOutDoesHWPlayThru : 0) |
(gCanAsync ? digiOutDoesAsyncGrabs : 0) |
(gDoesCompress ? digiOutDoesCompress : 0) |
((gDoesCompress && gOnlyDoesCompress) ? digiOutDoesCompressOnly : 0)
;
info->inputCurrentFlags = info->inputCapabilityFlags;
info->inputCurrentFlags |= digiInSignalLock;
info->outputCurrentFlags = 0;
if ((**storage).gAttachedGDevice)
info->outputCurrentFlags = (**(**(**storage).gAttachedGDevice).gdPMap).pixelSize;
else {
}
info->slot = 0; // we have no slot
info->gdh = (**storage).gAttachedGDevice;
info->maskgdh = 0;
info->minDestHeight = gMinHeight;
info->minDestWidth = gMinWidth;
info->maxDestHeight = gMaxHeight;
info->maxDestWidth = gMaxWidth;
info->blendLevels = 0;
info->reserved = 0;
(**storage).inputCurrentFlags = info->inputCurrentFlags;
(**storage).outputCurrentFlags = info->outputCurrentFlags;
return noErr;
}
pascal VideoDigitizerError vdigGetCurrentFlags(vdigGlobals storage, long *inputCurrentFlag, long *outputCurrentFlag)
{
*inputCurrentFlag = (**storage).inputCurrentFlags;
*outputCurrentFlag = (**storage).outputCurrentFlags;
return noErr;
}
pascal VideoDigitizerError vdigSetPlayThruOnOff(vdigGlobals storage, short state)
{
if (!gDoesPlaythru)
return digiUnimpErr;
(**storage).playThruOn = (state != 0);
return noErr;
}
pascal VideoDigitizerError vdigSetPlayThruDestination(vdigGlobals storage, PixMapHandle dest, Rect *dr, MatrixRecord *m, RgnHandle mask)
{
OSErr err;
short width, height;
Rect destRect;
if (!dest || (!dr && !m))
return paramErr;
if (dr)
destRect = *dr;
else {
if (GetMatrixType(m) > scaleTranslateMatrixType)
return matrixErr;
destRect = (**storage).digiRect;
TransformRect(m, &destRect, nil);
}
// make sure the rectangle is ok
if (EmptyRect(&destRect))
return paramErr;
if (mask && !gCanClip)
return paramErr;
if (!validatePixMap(storage, dest))
return paramErr;
if ((**storage).clipRgn) {
DisposeRgn((**storage).clipRgn);
(**storage).clipRgn = 0;
}
if (mask) {
HandToHand((Handle *)&mask);
if (err = MemError()) return err;
}
(**storage).clipRgn = mask;
(**storage).clipOrigin = *(Point *)&destRect;
{
Rect tempRect;
tempRect = destRect;
MapRect(&tempRect, &(**storage).digiRect, &(**storage).maxSrcRect); // convert to full frame
RectMatrix(&(**storage).matrix, &(**storage).maxSrcRect, &tempRect); // make a matrix
tempRect = (**storage).maxSrcRect;
TransformRect(&(**storage).matrix, &tempRect, 0);
width = tempRect.right - tempRect.left;
height = tempRect.bottom - tempRect.top;
}
if (width < gMinWidth || width > gMaxWidth || height < gMinHeight || height > gMaxHeight)
return paramErr;
#if 0
if (width != gMaxWidth || height != gMaxHeight)
return paramErr;
#endif
if (!gCanScale) {
short i = 3;
short tempWidth = gMaxWidth;
short tempHeight = gMaxHeight;
Boolean ok;
while (i--) {
ok = (width == tempWidth) && (height == tempHeight);
if (ok) break;
tempWidth >>= 1;
tempHeight >>= 1;
}
if (!ok)
return paramErr;
}
if ((**storage).tempPort) {
if ((**dest).pixelSize != (**(**storage).tempPort->portPixMap).pixelSize)
tossOffscreen(storage);
}
(**storage).playThruRect = destRect;
(**storage).playThruPixMap = dest;
return noErr;
}
// better checks for pixmap baseAddr matching could be done
Boolean validatePixMap(vdigGlobals storage, PixMapHandle p)
{
if ( !((**p).pixelSize & gDoesDepths) ) {
if (gCanDMA && ((**p).pixelSize & gDMADepths))
;
else
return false;
}
if (gCanDMA) // any other place is OK
return true;
if ((**storage).gAttachedGDevice) {
// see if pixels are on the device
if ((**p).baseAddr == (**(**(**storage).gAttachedGDevice).gdPMap).baseAddr)
return true;
}
if ((**storage).auxBuffer) {
if ((**p).baseAddr == (**(**storage).auxBuffer->portPixMap).baseAddr)
return true;
}
if (!(**storage).gAttachedGDevice) return true;
return false;
}
pascal VideoDigitizerError vdigPreflightDestination(vdigGlobals storage, Rect *digitizerRect, PixMap **dest, Rect *destRect, MatrixRecord *m)
{
//•• real code is required here in your vdig!!
return noErr;
}
pascal VideoDigitizerError vdigSetupBuffers(vdigGlobals storage, VdigBufferRecListHandle bufferList)
{
OSErr err;
MatrixRecord matrix;
short i;
RgnHandle clipRgn;
if (!bufferList)
return paramErr;
if (!(**bufferList).count)
return paramErr;
if ((**storage).bufferList) {
DisposHandle((Handle)(**storage).bufferList);
(**storage).bufferList = 0;
}
if ((**storage).clipRgn) {
DisposeRgn((**storage).clipRgn);
(**storage).clipRgn = 0;
}
if (!gCanClip && (**bufferList).mask)
return paramErr;
if ((**bufferList).matrix)
matrix = *(**bufferList).matrix;
// make a local copy of the buffer list
HandToHand((Handle *)&bufferList);
if (err = MemError()) return err;
if (clipRgn = (**bufferList).mask) {
HandToHand((Handle *)&clipRgn);
if (err = MemError()) return err;
(**storage).clipOrigin = (**bufferList).list[0].location;
}
(**storage).bufferList = bufferList;
(**storage).clipRgn = clipRgn;
(**storage).pendingAsyncBuffer = -1;
(**storage).matrix = matrix;
for (i=0; i < (**bufferList).count; i++) {
if (!validatePixMap(storage, (**bufferList).list[i].dest))
return paramErr;
// should check the point here too
}
return noErr;
}
pascal VideoDigitizerError vdigGrabOneFrameAsync(vdigGlobals storage, short buffer)
{
VdigBufferRecListHandle bufferList;
if (!gCanAsync)
return digiUnimpErr;
if (!(bufferList = (**storage).bufferList))
return badCallOrder;
if (buffer > (**bufferList).count)
return paramErr;
if ((**storage).pendingAsyncBuffer != -1) {
short aBuf = (**storage).pendingAsyncBuffer;
if (aBuf == buffer) DebugStr("\pasync grab into incomplete buffer");
drawVideoFrame(storage, (**bufferList).list[aBuf].location, (**bufferList).list[aBuf].dest);
}
(**storage).pendingAsyncBuffer = buffer;
return noErr;
}
pascal long vdigDone(vdigGlobals storage, short buffer)
{
vdigGlobalsPtr store = *storage;
VdigBufferRecListHandle bufferList;
if (!gCanAsync)
return 0;
if (!(bufferList = store->bufferList))
return 0;
if (buffer > (**bufferList).count)
return 0;
if (store->frameTimeStep && GetTimeBaseRate(store->timeBase)) {
if (GetTimeBaseTime(store->timeBase, gVideoTimeScale ? gVideoTimeScale : 600, nil) >= store->nextFrameTime)
store->nextFrameTime += store->frameTimeStep;
else
return false;
}
if (store->pendingAsyncBuffer == buffer) {
drawVideoFrame(storage, (**bufferList).list[buffer].location, (**bufferList).list[buffer].dest);
store->pendingAsyncBuffer = -1;
}
return true;
}
/*
inputs garbage
*/
pascal VideoDigitizerError vdigGetNumberOfInputs(vdigGlobals storage, short *inputs)
{
*inputs = 0;
return noErr;
}
pascal VideoDigitizerError vdigGetInputFormat(vdigGlobals storage, short input, short *format)
{
if (input == 0) {
*format = ntscIn;
return noErr;
}
else
return paramErr;
}
pascal VideoDigitizerError vdigSetInput(vdigGlobals storage, short input)
{
if (input == 0)
return noErr;
else
return paramErr;
}
pascal VideoDigitizerError vdigGetInput(vdigGlobals storage, short *input)
{
*input = 0;
return noErr;
}
/*
compressed source stuff
*/
void tossCompressStuff(vdigGlobals storage)
{
if ((**storage).compressSeq) {
CDSequenceEnd((**storage).compressSeq);
(**storage).compressSeq = 0;
}
if ((**storage).compressGW) {
DisposeGWorld((**storage).compressGW);
(**storage).compressGW = 0;
}
if ((**storage).compressBuffer) {
DisposPtr((**storage).compressBuffer);
(**storage).compressBuffer = 0;
}
if ((**storage).desc) {
DisposHandle((Handle)(**storage).desc);
(**storage).desc = 0;
}
}
pascal VideoDigitizerError vdigSetCompression(vdigGlobals storage, OSType compressType, short depth, Rect *bounds,
CodecQ spatialQuality, CodecQ temporalQuality, long keyFrameRate)
{
OSErr err;
GWorldPtr gw = 0;
long bufSize;
Ptr p;
ImageDescription ** tempImageDesc;
ImageSequence tempSeqId;
if (!gDoesCompress)
return digiUnimpErr;
tossCompressStuff(storage);
if (compressType == 'vpza')
compressType = 'rpza';
// see if we handle this compression
if (compressType && gOnlyCompressType &&
(compressType != gOnlyCompressType))
return noCodecErr;
if (!compressType) {
compressType = gOnlyCompressType ? gOnlyCompressType : 'rpza';
spatialQuality = codecNormalQuality;
temporalQuality = 0;
keyFrameRate = 0;
}
(**storage).compressType = compressType;
(**storage).compressDepth = depth ? depth : 16;
(**storage).compressRect = *bounds;
(**storage).spatialQuality = spatialQuality;
(**storage).temporalQuality = temporalQuality;
(**storage).keyFrameRate = keyFrameRate;
if (compressType == -1)
return noErr;
{
Rect tempRect;
tempRect = *bounds;
MapRect(&tempRect, &(**storage).digiRect, &(**storage).maxSrcRect); // convert to full frame
RectMatrix(&(**storage).matrix, &(**storage).maxSrcRect, &tempRect); // make a matrix
}
err = NewGWorld(&gw, depth, bounds, 0, 0, 0);
if (err) goto bail;
(**storage).compressGW = gw;
LockPixels(gw->portPixMap);
err = GetMaxCompressionSize(gw->portPixMap, bounds, depth, spatialQuality, compressType, bestSpeedCodec, &bufSize);
if (err) goto bail;
p = NewPtr(bufSize);
if (err = MemError()) goto bail;
(**storage).compressBuffer = p;
tempImageDesc = (ImageDescription **)NewHandle(sizeof(ImageDescription));
if (err = MemError()) goto bail;
(**storage).desc = tempImageDesc;
// fill this out for now.. mark will help us out later
(**tempImageDesc).temporalQuality = temporalQuality;
(**tempImageDesc).spatialQuality = spatialQuality;
(**tempImageDesc).width = bounds->right - bounds->left;
(**tempImageDesc).height = bounds->bottom - bounds->top;
(**tempImageDesc).depth = (compressType == 'rpza') ? 16 : depth;
(**tempImageDesc).cType = compressType;
(**tempImageDesc).hRes = 0x00480000;
(**tempImageDesc).vRes = 0x00480000;
err = CompressSequenceBegin(&tempSeqId,
gw->portPixMap, (PixMap **)0,
bounds, (Rect *)0,
depth, compressType, bestSpeedCodec, spatialQuality,
temporalQuality, keyFrameRate, (CTabHandle )0,
codecFlagUpdatePrevious, tempImageDesc );
if (err) goto bail;
(**storage).compressSeq = tempSeqId;
bail:
if (err)
tossCompressStuff(storage);
return err;
}
pascal VideoDigitizerError vdigCompressOneFrameAsync(vdigGlobals storage)
{
if (!gDoesCompress)
return digiUnimpErr;
if (!(**storage).compressSeq)
return badCallOrder;
// draw the offscreen now, compress later...
drawVideoFrame(storage, *(Point *)&(**storage).compressRect, (**storage).compressGW->portPixMap);
return noErr;
}
pascal VideoDigitizerError vdigCompressDone(vdigGlobals storage, Boolean *done, Ptr *theData, long *dataSize, unsigned char *similarity, TimeRecord *tr)
{
vdigGlobalsPtr store = *storage;
OSErr err;
Rect r;
*done = true;
if (!gDoesCompress)
return digiUnimpErr;
if (!store->compressSeq)
return badCallOrder;
if (store->frameTimeStep && GetTimeBaseRate(store->timeBase)) {
if (GetTimeBaseTime(store->timeBase, gVideoTimeScale ? gVideoTimeScale : 600, nil) >= store->nextFrameTime)
store->nextFrameTime += store->frameTimeStep;
else {
*done = false;
return noErr;
}
}
r = store->compressRect;
err = (OSErr)CompressSequenceFrame(store->compressSeq, store->compressGW->portPixMap, &r,
codecFlagUpdatePrevious | (store->forceKeyFrame ? codecFlagForceKeyFrame : 0),
store->compressBuffer, dataSize, similarity, (CompletionProcRecordPtr)0);
store = *storage;
*theData = store->compressBuffer;
store->forceKeyFrame = false;
GetTimeBaseTime(store->timeBase, 30, tr);
return err;
}
pascal VideoDigitizerError vdigReleaseCompressBuffer(vdigGlobals storage, Ptr theBufffer)
{
if (!gDoesCompress)
return digiUnimpErr;
if (!(**storage).compressSeq)
return badCallOrder;
//•• could actually track this...
//•• could pound part of buffer to 0 or something
return noErr;
}
pascal VideoDigitizerError vdigGetImageDescription(vdigGlobals storage, ImageDescriptionHandle desc)
{
OSErr err = noErr;
if (!gDoesCompress)
return digiUnimpErr;
if ((**storage).desc) {
long dataSize;
SetHandleSize((Handle)desc, dataSize = GetHandleSize((Handle)(**storage).desc));
if (err = MemError()) goto bail;
BlockMove((Ptr)*(**storage).desc, (Ptr)*desc, dataSize);
}
else
err = badCallOrder;
bail:
return err;
}
pascal VideoDigitizerError vdigResetCompressSequence(vdigGlobals storage)
{
OSErr err = noErr;
if (!gDoesCompress)
return digiUnimpErr;
(**storage).forceKeyFrame = true;
return err;
}
pascal VideoDigitizerError vdigSetCompressionOnOff(vdigGlobals storage, Boolean newState)
{
OSErr err = noErr;
if (!gDoesCompress)
return digiUnimpErr;
if (newState != (**storage).compressOn) {
(**storage).compressOn = newState;
if (!(**storage).compressOn)
tossCompressStuff(storage);
}
return err;
}
pascal VideoDigitizerError vdigGetCompressionTypes(vdigGlobals storage, VDCompressionListHandle h)
{
CodecInfo info;
CodecType cType;
CodecComponent codec;
VDCompressionListPtr p;
GetCodecInfo(&info, 'rpza', 0);
SetHandleSize((Handle)h, sizeof(VDCompressionList));
p = &(*h)[0];
BlockMove(info.typeName, p->typeName, 32);
p->typeName[++p->typeName[0]] = ' ';
p->typeName[++p->typeName[0]] = 'V';
p->typeName[++p->typeName[0]] = 'D';
p->typeName[++p->typeName[0]] = 'I';
p->typeName[++p->typeName[0]] = 'G';
BlockMove(p->typeName, p->name, 64);
p->codec = 0;
p->cType = 'rpza';
p->formatFlags = info.formatFlags;
p->compressFlags = info.compressFlags;
return noErr;
}
pascal VideoDigitizerError vdigSetTimeBase(vdigGlobals storage, TimeBase t)
{
(**storage).timeBase = t;
return noErr;
}
pascal VideoDigitizerError vdigSetFrameRate(vdigGlobals storage, Fixed framesPerSecond)
{
vdigGlobalsPtr store = *storage;
if (!gDoesFrameRate)
return digiUnimpErr;
if (framesPerSecond < 0)
return paramErr;
store->nextFrameTime = store->frameTimeStep = 0;
if (framesPerSecond)
store->frameTimeStep = FixDiv(gVideoTimeScale ? gVideoTimeScale : 600, framesPerSecond);
return noErr;
}
pascal VideoDigitizerError vdigGetDMADepths(vdigGlobals storage, long *depthArray, long *preferredDepth)
{
if (!gCanDMA)
return paramErr;
*depthArray = gDMADepths;
// *preferredDepth = gDMADepths & 16;
*preferredDepth = 40;
// kck *preferredDepth = 8;
return noErr;
}
pascal VideoDigitizerError vdigGetPreferredTimeScale(vdigGlobals storage, TimeScale *preferred)
{
if (gVideoTimeScale) {
*preferred = gVideoTimeScale;
return noErr;
}
else
return badComponentSelector;
}